﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ServerNodeGui
{
	public partial class MainWindow : Form
	{
		protected ServerNodeLib.PersistentSchedulerServer schedulerServer;

		public MainWindow()
		{
			InitializeComponent();
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			this.Icon = CommonLib.CommonResources.CommonIcon;
			//schedulerServer = new ServerNodeLib.RoundRobinSchedulerServer();
			schedulerServer = new ServerNodeLib.PersistentSchedulerServer();
			schedulerServer.OnServerToggled += new Action(this.HandleSchedulerToggled);
			//schedulerServer.LoadState();
			schedulerServer.Start();

			dataGridBatches.DataSource = schedulerServer.Batches;
			dataGridNodes.DataSource = schedulerServer.Nodes;
			dataGridLog.DataSource = CommonLib.Logger.Instance.LogTable;

			schedulerServer.OnStateChanged += new Action(this.HandleSchedulerStateChanged);

			// output example since I haven't finished the wizard yet
			using (System.IO.StreamWriter writer = new System.IO.StreamWriter("DefaultTemplate.xml"))
			{
				System.Xml.Serialization.XmlSerializer s = new System.Xml.Serialization.XmlSerializer(typeof(ServerNodeLib.BatchTemplate));
				ServerNodeLib.BatchTemplate bt = new ServerNodeLib.BatchTemplate();
				ServerNodeLib.BatchCommand bc = new ServerNodeLib.BatchCommand();
				bc.Command = @"notepad.exe";
				bc.MinTimeSeconds = 10;
				bc.MaxTimeSeconds = 20;
				bc.ErrorOnTimeOut = true;
				bc.Arguments = String.Empty;
				bt.BaseBatch.BatchCommands.Add (bc);
				ServerNodeLib.BatchResource br = new ServerNodeLib.BatchResource();
				br.ClientPath = @"C:\temp%i%.txt";
				br.ServerPath = @"C:\temp%j%.txt";
				bt.BaseBatch.BatchResources.Add(br);
				ServerNodeLib.BatchResource br2 = new ServerNodeLib.BatchResource();
				br2.ClientPath = @"C:\temp.txt";
				br2.ServerPath = @"C:\temp.txt";
				bt.BaseBatch.ReturnResources.Add(br2);
				bt.Name = @"Default Template.  Edit on your own whim";
				bt.BaseBatch.Comments = @"%j% (j) = %i% (i) + 1";
				bt.BaseBatch.LogFilenameFormat = @"HarnessResults%i%.xml";
				bt.BaseBatch.BatchGroup = Guid.Empty ;
				bt.StartConfigIndex = 0;
				bt.EndConfigIndex = 4;
				s.Serialize(writer, bt);
				writer.Close();
			}
		}

		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);
			schedulerServer.Stop();
			//schedulerServer.SaveState();
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void addTemplateToolStripMenuItem_Click(object sender, EventArgs e)
		{
			try
			{
				OpenBatchTemplateDialog obtd = new OpenBatchTemplateDialog();
				if (obtd.ShowDialog() == DialogResult.OK)
				{
					schedulerServer.AddBatchTemplate(obtd.Template, obtd.OutputDirectory, obtd.Comments);
				}
			}
			catch (Exception ex)
			{
				// log the exception
				CommonLib.Logger.Instance.Report(CommonLib.LogType.Error, this, ex.Message);
			}
		}

		private void nodesToolStripDropNodeBtn_Click(object sender, EventArgs e)
		{
			try
			{
				List<Guid> toRemove = new List<Guid>();
				foreach (DataGridViewRow row in dataGridNodes.SelectedRows)
				{
					DataRowView rowView = row.DataBoundItem as DataRowView;
					if (rowView == null)
						continue;
					if (rowView.Row == null)
						continue;
					toRemove.Add((Guid)rowView.Row[ServerNodeLib.NodesTableKeys.NodeId]);
				}
				foreach (Guid row in toRemove)
				{
					schedulerServer.DropNode(row);
				}
			}
			catch (Exception)
			{

			}
		}

		private void nodesToolStripKillBatchestn_Click(object sender, EventArgs e)
		{
			try
			{
				foreach (DataGridViewRow row in dataGridNodes.SelectedRows)
				{
					DataRowView rowView = row.DataBoundItem as DataRowView;
					if (rowView == null)
						continue;
					if (rowView.Row == null)
						continue;
					schedulerServer.ResetNode((Guid)rowView.Row[ServerNodeLib.NodesTableKeys.NodeId]);
				}
			}
			catch (Exception)
			{

			}
		}

		private void createTemplateToolStripMenuItem_Click(object sender, EventArgs e)
		{
			NewTemplateWizard();
		}

		private void batchesToolStripNewWizard_Click(object sender, EventArgs e)
		{
			NewTemplateWizard();
		}

		private void NewTemplateWizard()
		{
			MessageBox.Show("I know how this looks, but the wizard is not yet complete.\r\nPlase edit the XML def by hand.", "I'm Sorry!");
		}

		private void batchesToolStripOpenTemplate_Click(object sender, EventArgs e)
		{
			addTemplateToolStripMenuItem_Click(sender, e);
		}

		private void batchesToolStripDropBatchBtn_Click(object sender, EventArgs e)
		{
			List<Guid> toRemove = new List<Guid>();
			foreach (DataGridViewRow row in dataGridBatches.SelectedRows)
			{
				DataRowView rowView = row.DataBoundItem as DataRowView;
				if (rowView == null)
					continue;
				if (rowView.Row == null)
					continue;
				toRemove.Add((Guid)rowView.Row[ServerNodeLib.BatchTableKeys.BatchId]);
			}
			foreach (Guid row in toRemove)
			{
				schedulerServer.DropBatch(row);
			}
		}

		private void batchesToolStripResetBatch_Click(object sender, EventArgs e)
		{
			foreach (DataGridViewRow row in dataGridBatches.SelectedRows)
			{
				DataRowView rowView = row.DataBoundItem as DataRowView;
				if (rowView == null)
					continue;
				if (rowView.Row == null)
					continue;
				Guid g = (Guid)rowView.Row[ServerNodeLib.BatchTableKeys.BatchId];
				schedulerServer.ResetBatch(g);
			}
		}
		#region update gui info

		public void UpdateIdleNodes(String newString)
		{
			/*
			if(nodesToolStripNumTotal.InvokeRequired)
			{
				NotifyRefresh d = new NotifyRefresh(this.UpdateIdleNodes);
				this.Invoke(d, newString);
			}
			else
			{
				this.nodesToolStripNumTotal.Text = newString;
			}
			*/
			this.nodesToolStripNumTotal.Text = newString;
		}
		public void UpdateIdleBatches(String newString)
		{
			/*
			if (batchesToolStripNumNodes.InvokeRequired)
			{
				NotifyRefresh d = new NotifyRefresh(this.UpdateIdleBatches);
				this.Invoke(d, newString);
			}
			else
			{
				this.batchesToolStripNumNodes.Text = newString;
			}
			*/
			this.batchesToolStripNumNodes.Text = newString;
		}
		private void HandleSchedulerStateChanged()
		{
			int totalBatches = schedulerServer.TotalBatches;
			int activeBatches = totalBatches - schedulerServer.QueuedBatches;
			UpdateIdleBatches(String.Format("{0} / {1}", activeBatches, totalBatches));

			int totalNodes = schedulerServer.TotalNodes;
			int activeNodes = totalNodes - schedulerServer.IdleNodes;
			UpdateIdleNodes(String.Format("{0} / {1}", activeNodes, totalNodes));
		}

		private void HandleSchedulerToggled()
		{
			if (schedulerServer.IsRunning())
			{
				nodesToolStripActive.Image = GuiResources.ImageGo;
				nodesToolStripActive.Text = GuiResources.SchedulerStateActive;
			}
			else
			{
				nodesToolStripActive.Image = GuiResources.ImageStop;
				nodesToolStripActive.Text = GuiResources.SchedulerStateNotActive;
			}
		}

		private delegate void NotifyRefresh(String newString);
		#endregion

		private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
		{
			try
			{
				AboutDialog ad = new AboutDialog();
				ad.ShowDialog();
			}
			catch (Exception)
			{

			}
		}

		private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (schedulerServer == null)
				return;
			ServerOptionsDialog od = new ServerOptionsDialog();
			od.BatchResultsFolder = schedulerServer.Settings.ResultResourceDirectory;
			if (od.ShowDialog() == DialogResult.OK)
			{
				// check again
				if(System.IO.Directory.Exists(od.BatchResultsFolder))
					schedulerServer.Settings.ResultResourceDirectory = od.BatchResultsFolder;
			}
		}

		private void nodeToolStripProperties_Click(object sender, EventArgs e)
		{
			try
			{
				if (dataGridNodes.SelectedRows.Count > 0)
				{
					DataGridViewRow selectedViewRow = dataGridNodes.SelectedRows[0];
					DataRow selectedRow = (selectedViewRow.DataBoundItem as DataRowView).Row;
					NodeDetailsDialog nd = new NodeDetailsDialog();
					Guid nodeId = (Guid)selectedRow[ServerNodeLib.NodesTableKeys.NodeId];
					ServerNodeLib.Node n = schedulerServer.GetNode(nodeId);
					if(n == null)
						return;
					nd.NodeId = n.NodeId;
					nd.NodeName = n.NodeName;
					int longtimeout = n.NormalTimeout;
					int shorttimeout = n.ErrorTimeout;
					nd.LongTimeout = longtimeout;
					nd.ShortTimeout = shorttimeout;
					nd.AcceptNewJobs = n.AcceptNewJobs;
					nd.QueueLength = n.ResponseQueue.Count;
					if (nd.ShowDialog() == DialogResult.OK)
					{
						// only send updates to fields that change
						if (nd.NodeName.Equals(n.NodeName) == false)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.NodeName,
									nd.NodeName
								)
							);
						}
						bool ndAccept = nd.AcceptNewJobs; // fixes compiler issue
						if (ndAccept.Equals(n.AcceptNewJobs) == false)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.AcceptNewJobs,
									ndAccept.ToString()
								)
							);
						}
						int newLongTimeout = nd.LongTimeout;
						if (newLongTimeout != longtimeout)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.LongTimeout,
									newLongTimeout.ToString()
								)
							);
						}
						int newShortTimeout = nd.ShortTimeout;
						if (newShortTimeout != shorttimeout)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.ShortTimeout,
									newShortTimeout.ToString()
								)
							);
						}
					}
				}
			}
			catch (Exception ex)
			{
				CommonLib.Logger.Instance.Report(CommonLib.LogType.Error, this, ex.Message);
			}
		}

		private void toolStripLogDelete_Click(object sender, EventArgs e)
		{
			try
			{
				lock (CommonLib.Logger.Instance.LogTable)
				{
					List<DataRow> toRemove = new List<DataRow>();
					foreach (DataGridViewRow viewRow in dataGridLog.SelectedRows)
					{
						DataRow row = (viewRow.DataBoundItem as DataRowView).Row;
						toRemove.Add(row);
					}
					foreach (DataRow row in toRemove)
					{
						CommonLib.Logger.Instance.LogTable.Rows.Remove(row);
					}
				}
			}
			catch (Exception)
			{

			}
		}

		private void documentationToolStripMenuItem_Click(object sender, EventArgs e)
		{
			WebBrowser wb = new WebBrowser();
			// lol, I really shouldn't hard-code this!
			wb.Navigate("http://www.codeplex.com/WinParallelScheduler", true);
			wb.Dispose();
		}

		private void nodesToolStripActive_Click(object sender, EventArgs e)
		{
			if (schedulerServer.IsRunning())
			{
				schedulerServer.Stop();
			}
			else
			{
				schedulerServer.Start();
			}
		}

		private void toolStripFiles_Click(object sender, EventArgs e)
		{
			try
			{
				if (dataGridNodes.SelectedRows.Count > 0)
				{
					DataGridViewRow selectedViewRow = dataGridNodes.SelectedRows[0];
					DataRow selectedRow = (selectedViewRow.DataBoundItem as DataRowView).Row;
					NodeDetailsDialog nd = new NodeDetailsDialog();
					Guid nodeId = (Guid)selectedRow[ServerNodeLib.NodesTableKeys.NodeId];
					ServerNodeLib.Node n = schedulerServer.GetNode(nodeId);
					if (n == null)
						return;
					nd.NodeId = n.NodeId;
					nd.NodeName = n.NodeName;
					int longtimeout = n.NormalTimeout;
					int shorttimeout = n.ErrorTimeout;
					nd.LongTimeout = longtimeout;
					nd.ShortTimeout = shorttimeout;
					nd.AcceptNewJobs = n.AcceptNewJobs;
					nd.QueueLength = n.ResponseQueue.Count;
					if (nd.ShowDialog() == DialogResult.OK)
					{
						// only send updates to fields that change
						if (nd.NodeName.Equals(n.NodeName) == false)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.NodeName,
									nd.NodeName
								)
							);
						}
						bool ndAccept = nd.AcceptNewJobs; // fixes compiler issue
						if (ndAccept.Equals(n.AcceptNewJobs) == false)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.AcceptNewJobs,
									ndAccept.ToString()
								)
							);
						}
						int newLongTimeout = nd.LongTimeout;
						if (newLongTimeout != longtimeout)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.LongTimeout,
									newLongTimeout.ToString()
								)
							);
						}
						int newShortTimeout = nd.ShortTimeout;
						if (newShortTimeout != shorttimeout)
						{
							schedulerServer.EnqueueActionRequest(nodeId,
								new ServerNodeLib.ActionRequest(
									ServerNodeLib.ActionRequestType.ChangeSetting,
									ServerNodeLib.ClientSettingKeys.ShortTimeout,
									newShortTimeout.ToString()
								)
							);
						}
					}
				}
			}
			catch (Exception ex)
			{
				CommonLib.Logger.Instance.Report(CommonLib.LogType.Error, this, ex.Message);
			}
		}
	}
}
